package com.alien.admin.modules.gitlab.service.utils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.MergeRequestApi;
import org.gitlab4j.api.models.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.List;

/**
 * Copyright (C), 2014-2021, 厦门神州鹰软件科技有限公司
 * FileName: GitLabServiceUtils
 *
 * @author: zengzf
 * Date:     2021/9/8 19:01
 * Description:
 * History:
 */
@Component
@Slf4j
@Data
public class GitLabServiceUtils {

    @Value("${gitlab.host}")
    private String host;


    /**
     * 获取所有gitLab上的所有项目
     *
     * @return
     * @throws IOException
     * @throws GitLabApiException
     */
    public List<Project> getAllProject(String privateToken) throws IOException, GitLabApiException {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        List<Project> projects = gitLabApi.getProjectApi().getProjects();
        return projects;
    }

    /**
     * 获得某个项目的所有分支。
     * 如果要模糊搜索，可以在这个基础上操作。
     *
     * @param projectId 344
     * @return
     * @throws GitLabApiException
     */
    public List<Branch> getBranches(String privateToken, Integer projectId) throws GitLabApiException {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        List<Branch> branchList = gitLabApi.getRepositoryApi().getBranches(projectId);
        return branchList;
    }

    public Branch getBranch(String privateToken, Integer projectId, String branchName) throws GitLabApiException {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        return gitLabApi.getRepositoryApi().getBranch(projectId, branchName);
    }

    /**
     * 获取tag
     *
     * @return
     * @throws GitLabApiException
     */
    public List<Tag> getTags(String privateToken, Integer projectId) throws GitLabApiException {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        List<Tag> tagList = gitLabApi.getTagsApi().getTags(projectId);
        return tagList;
    }

    /**
     * 创建一个新的分支
     *
     * @param projectId
     * @param newBranchName
     * @param fromBranchName
     * @throws GitLabApiException
     */
    public void createBranch(String privateToken, Integer projectId, String newBranchName, String fromBranchName) {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        Branch branch = null;
        try {
            branch = gitLabApi.getRepositoryApi().getBranch(projectId, newBranchName);
        } catch (GitLabApiException e) {
            e.getHttpStatus();
        }
        if (branch == null) {
            try {
                gitLabApi.getRepositoryApi().createBranch(projectId, newBranchName, fromBranchName);
            } catch (GitLabApiException e) {
                e.printStackTrace();
            }
        } else {
            log.info("newBranchNameHasExist! projectId:{}, newBranchName:{}", projectId, newBranchName);
        }
    }

    /**
     * 删除一个分支
     *
     * @throws GitLabApiException
     */
    public void deleteBranch(String privateToken, Integer projectId, String branchName) {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        try {
            gitLabApi.getRepositoryApi().deleteBranch(projectId, branchName);
            log.info("deleteBranchSuccessful! projectId:{}, branchName:{}", projectId, branchName);
        } catch (GitLabApiException e) {
            e.printStackTrace();
        }
    }

    /**
     * 合并某个分支.
     * <p>
     * 可能会有异常。如果发生异常，那么会影响下一次合并！
     *
     * @param projectId
     * @param fromBranch
     * @param toBranch
     * @param comment
     * @throws GitLabApiException
     */
    public void merge(String privateToken, Integer projectId, String fromBranch, String toBranch, String comment) throws GitLabApiException {

        GitLabApi gitLabApi = new GitLabApi(host, privateToken);

        MergeRequestApi mergeRequestApi = gitLabApi.getMergeRequestApi();

        MergeRequest mergeRequest = findMergeRequest(gitLabApi, projectId, fromBranch, toBranch);
        if(mergeRequest == null) {
            MergeRequestParams mergeRequestParams = new MergeRequestParams();
            mergeRequestParams.withSourceBranch(fromBranch).withTargetBranch(toBranch).withTitle(comment);
            mergeRequest = mergeRequestApi.createMergeRequest(projectId, mergeRequestParams);
            log.info("step1:mergeRequest");
        }

        Integer mergeRequestId = mergeRequest.getIid();
        MergeRequest mergeRequestChange = mergeRequestApi.getMergeRequestChanges(projectId, mergeRequestId);

        if(mergeRequestChange.getChanges().isEmpty()) {
            // 无修改，不需要合并
            //mergeRequestApi.deleteMergeRequest(projectId, mergeRequest.getIid());
            return;
        }

        if(mergeRequestChange.getHasConflicts()) {
            // close掉合并请求
            mergeRequestApi.deleteMergeRequest(projectId, mergeRequest.getIid());
            throw new GitLabApiException("代码存在冲突，无法合并，请开发人员处理合并后再部署!");
        }

        mergeRequestApi.approveMergeRequest(projectId, mergeRequestId, mergeRequest.getSha());
        log.info("step2:approveMergeRequest");

        mergeRequestApi.acceptMergeRequest(projectId, mergeRequestId);
        log.info("step3:acceptMergeRequest");
    }

    private MergeRequest findMergeRequest(GitLabApi gitLabApi, Integer projectId, String source, String target) throws GitLabApiException {
        MergeRequestApi mergeRequestApi = gitLabApi.getMergeRequestApi();
        List<MergeRequest>  mergeRequests = mergeRequestApi.getMergeRequests(projectId);
        int mergeRequestCount = mergeRequests.size();
        for(int index = 0; index < mergeRequestCount; index++) {
            MergeRequest request = mergeRequests.get(index);
            if(request.getSourceBranch().equals(source)
                    && request.getTargetBranch().equals(target)
                    && request.getState().equals("opened")) {
                return request;
            }
        }

        return null;
    }

    /**
     * 关闭某次合并请求
     *
     * @param projectId
     * @param mergeRequestId
     * @throws GitLabApiException
     */
    public void close(String privateToken, Integer projectId, Integer mergeRequestId) throws GitLabApiException {
        GitLabApi gitLabApi = new GitLabApi(host, privateToken);
        gitLabApi.getMergeRequestApi().getClosesIssues(projectId, mergeRequestId);
    }
}

